// 常用工具方法集

import {each} from 'lodash'

var dep$ = window.jQuery || window._ || _;

String.prototype.endsWith = function(pattern) {	var d = this.length - pattern.length;	return d >= 0 && this.lastIndexOf(pattern) === d;};
String.prototype.startsWith = function(pattern) {return this.indexOf(pattern) === 0;};

if(!window.contextRoot){
	//如果flag不为空，则根据flag来定位是否有appcontext URI
	var flag1 = "static",flag2 = "tch_",flag3 = "stu_",url=location.href;
	window.contextRoot="";
	var uc = new RegExp(/^[a-zA-z]+:\/\/([a-zA-Z0-9\-\.]+(:[0-9]{1,}){0,1})(\/[^\/]+)([\/\-\w .?%&#=:]*)+$/);
	if(uc.test(url)) {
		var match = uc.exec(url);
		var capUri = match[3];//从url中获取到的context路径
		var host = match[1];
		window.contextRoot =  (capUri.startsWith(flag1) || capUri.startsWith(flag2)||capUri.startsWith(flag3))? "":capUri;
	}
}
if(!window.domain){
	window.domain = "localhost";window.apiPort = ":8090";
	//如果再生产或dev环境则忽略上面的测试配置
	if(location.href.indexOf("kolabao.com")>=0 || location.href.indexOf("beikexiaoyuan.com")>=0){
		domain = host;	apiPort = "";
	}
}
if(!window.mvcRoot){
	window.mvcRoot = "http://"+domain+apiPort+"/smvc"; //支持上下文参数为空或者为一个单词
}
if(!window.require) {
	window.require = function(){};
}

var RMX = window.RMX = dep$.extend(window.RMX||{},{
	obtainUrlContext : function(url,flag){
		//如果flag不为空，则根据flag来定位是否有appcontext URI
		var uc = new RegExp(/^[a-zA-z]+:\/\/[a-zA-Z0-9\-\.]+(:[0-9]{1,}){0,1}(\/[^\/]+)([\/\-\w .?%&#=:]*)+$/);
		if(uc.test(url)) {
			var capUri = uc.exec(url)[2];//从url中获取到的context路径
			return flag && capUri.endsWith(flag)? "":capUri;
		}else
			return "";
	},
	getUrlParam : function(pname) {
		var name, value;
		var str = location.href; //取得整个地址栏
		var num = str.indexOf("?");
		str = str.substr(num + 1); //取得所有参数
		var arr = str.split("&"); //各个参数放到数组里
		for ( var i = 0; i < arr.length; i++) {
			num = arr[i].indexOf("=");
			if (num > 0) {
				name = arr[i].substring(0, num);
				value = arr[i].substr(num + 1);
				if (pname === name)
					return decodeURIComponent(value);
			}
		}
		return "";
	},
	getUrlIntParam : function(name) {
		var ret = RMX.getUrlParam(name);
		if (ret.isInteger())
			return ret;
		else
			return 1;
	},
	putRandomToUrl : function(url) {
		if (url.indexOf("?") < 0)
			return url + "?mid=" + Math.random();
		else
			return url + "&mid=" + Math.random();
	},
	/**
	 *
	 * @param {Object} url
	 * @param {Object} params
	 * @param {Object} noRandom 如果指定为true则向不向url中添加随即数
	 * @return {TypeName}
	 */
	getUrl : function(url, params, noRandom) {
		var _hw = url.indexOf("?") < 0;
		var _ps = (noRandom?"":("mid=" + Math.random()))+(!params?"":(_hw&&noRandom?"":"&"+dep$.param(params||{})));
		return url + (_ps?(_hw?"?":"&")+_ps:"");
	},
	/**
	 * 此方法将重构json保障其内部的有效性。把含有json字符串的string都转义为object
	 * @param {Object} json
	 * @return {Object}
	 */
	evalWholeJson : function(json,evalProp) {
		try{
			if (json instanceof Array|| json instanceof Object) {
				_.each(json,function (o, n) {
					if (typeof (o) == "string") {//根节点json如果为字符串可以没有{}开头和结束，但是如果对Object 评估，则要求属性中必须包含{}开头和结束，否则根本不知道是字符串还是需要评估的json字符
						if (o.charAt(0) == "{" && o.charAt(o.length - 1) == "}")
							json[n] = eval("(" + json[n] + ")");
					} else if(o instanceof Array || o instanceof Object) {
						RMX.evalWholeJson(o,evalProp);//评估对象是可以不用返回值的，评估字符和数组是必须返回值的。
					}

					//将属性也评估了
					evalProp && typeof n ==='string' && (n.indexOf('.')>0 || n.indexOf("[")>0) && RMX.flatVal(n,o,json) && (delete json[n])

				})
			} else if(typeof (json) == "string"){//根节点json如果为字符串可以没有{}开头和结束，但是如果对Object 评估，则要求属性中必须包含{}开头和结束，否则根本不知道是字符串还是需要评估的json字符
				return json.charAt(0) == "{"? eval("(" + json + ")"): eval("({" + json + "})");
			}
		}catch(e){
			console.error("evalWholeJson 错误，json=", json, e);
			return null;
		}

	},
	/**字符串默认值和ng默认值功能*/
	rmxOption : function (scope, directiveName,directiveAttr) {
		scope.rmxOption && (scope[directiveName] = _.isFunction(scope.rmxOption)?scope.rmxOption():scope.rmxOption);
		!scope[directiveName] && directiveAttr && (scope[directiveName] = RMX.evalWholeJson(directiveAttr));
		scope[directiveName]= scope[directiveName]||{};
		return scope[directiveName];
	},
	/**
	 * 此方法将返回保证其没有null的属性obj，并转换string的"ture"、"false"为对应的boolean
	 * @param {Object} obj
	 * @return {TypeName}
	 */
	getValidPropsObj : function(obj) {
		if (obj instanceof Array) {
			var i = obj.length;
			while (i--) {
				obj[i] = RMX.getValidPropsObj(obj[i]);
			}
			return obj;
		} else if (obj instanceof Object) {
			var newObj = {};
			for ( var i in obj) {
				if (obj[i]) {
					if (obj[i] instanceof Array)
						newObj[i] = RMX.getValidPropsObj(obj[i]);
					else {
						newObj[i] = obj[i];
						if (obj[i] == "true")
							newObj[i] = true;
						else if (obj[i] == "false")
							newObj[i] = false;
					}
				} else {
				}//不填写则删除了空属性
			}
			return newObj;
		}
	},
	getRoandomInt : function() {
		r = Math.random();
		return Math.round(r * 1000000);
	},
	/**功能函数 对象写入属性
	 *
	 * @param obj  普通JS对象
	 * @param selector JQUERY ID选择器 例如传入 "#elementid" 选择的就是页面中ID=elementid的DOM对象
	 */
	writeObj2val : function (obj, selector,pres) {
		//tarArea 范围性结果集
		var tarArea = jQuery(selector);
		for ( var prop in obj) {
			var value =obj[prop];
			var propLowerFirstChar=prop.replace(/^\w/g,function(s){	return s.toUpperCase();	});
			if(!!value)
				if(!pres){
//					var t = document.getElementById(prop);
//					if(t) t.value=value;
					tarArea.find("#" + prop).val(value);
				}else{
					//	var presProps ="#" + pres[0] + propLowerFirstChar;
					for(var i=0,c=pres.length;i<c;i++){
						tarArea.find(pres[i] + propLowerFirstChar).val(value);
//						var t =	document.getElementById(pres[i] + propLowerFirstChar);
//						if(t) t.value=value;
					}
					//	presProps+=",#" + pres[i] + propLowerFirstChar;
					//	tarArea.find(presProps).val(value);
				}
		}
	},
	/** */
	copyProperties : function (obj, destSelector,valueMethod,pres) {
		//tarArea 范围性结果集
		var tarArea = jQuery(destSelector);
		var valMethod = dep$.fn[valueMethod ||  "val"];
		for ( var prop in obj) {
			var value =obj[prop];
			var propLowerFirstChar=prop.replace(/^\w/g,function(s){	return s.toUpperCase();	});
			if(!!value)
				if(!pres){
//					var t = document.getElementById(prop);
//					if(t)t.innerText=value;
					valMethod.apply(tarArea.find("[rid='" + prop+"']"),[value]);
				}else{
					//	var presProps ="#" + pres[0] + propLowerFirstChar;
					for(var i=0,c=pres.length;i<c;i++){
//						var t =	document.getElementById(pres[i] + propLowerFirstChar);
//						if(t)t.innerText=value;
						tarArea.find("[rid='" + pres[i] + propLowerFirstChar+"']").text(value);
					}
					//	presProps+=",#" + pres[i] + propLowerFirstChar;
					//	tarArea.find(presProps).val(value);
				}
		}
	},
	//访问链必须符合js规则。
	flatVal : function(flatStr,value,context/*inner*/,reg){
		var paramNameReg = reg || (/^([A-Za-z_]\w*)|(\.([A-Za-z_]\w*))|(\[(\d+)\])|(\[(\"[^\"]*\")])|(\[(\'[^\']*\')])/g);
		var b=n=e=0,ec,ctx=context, // i是正则本次匹配的开始，e是匹配的末尾,ec是末尾的下一个字符，c是总长度，n是上次匹配末尾的位置
			g=0,//匹配上的组号
			s=flatStr,c=s.length,mr,idx;
		var doFlatVal = false;
		while((mr=paramNameReg.exec(flatStr))){
			if(n!=(b=mr.index)){
				throw {name:'格式异常',message:'链式访问格式异常，字符串中间有非法字符'}
			}

			doFlatVal = true;
			if((idx=mr[(g=1)]||mr[(g=3)]||mr[(g=5)]||mr[(g=7)]||mr[(g=9)]) && (e=b+mr[0].length)===c){
				idx=g==5?parseInt(idx):idx;
				ctx[idx]=value;
				break;
			}

			if(!ctx[idx])
				ctx[idx]= ((ec=s.charAt(e))=='.')?{} // 新增{}
					: (ec=='['?[] //新增[]
					:undefined); //抛出异常

			if(!ctx[idx])
				throw {name:'格式异常',message:'链式访问格式异常，此处应该为.或['};

			n=e;
			ctx=ctx[idx];
		}
		return doFlatVal;
	},
	flat2tree : function(flatDatas,treeSettings) {
		var dnode = {fields: [], subNodes: {}};
		//var defaultNodes = {
		//	nodeName:"id",
		//	fields:['field1','field2'],
		//	subNodes:{
		//		type:'list' or 'object'
		//		nodeName:{
		//			fields:[],
		//			subNodes:{},
		//			subLists:{}
		//		}
		//	},
		//	subLists: {
		//		nodeName: {
		//			fields: [],
		//			subNodes:{},
		//			subLists:{}
		//		}
		//	}
		//};
		var createSettings = function(data,nodeSettings){
			var ns = dep$.extend(true,{},dnode,nodeSettings);
			_.each(data, function (v, key) {
				if (key.indexOf(".") < 0 && key.indexOf("[") < 0) {
					ns.fields.push(key);
				}else{//进到这里面来的要么有符号. 要么有符号[
					var ctx=ns;//设置根节点
					var paramNameReg = (/^([A-Za-z_][A-Za-z\d_]*)|(\.([A-Za-z_][A-Za-z\d_]*))|(\[([\d\w]+)\])|(\[(\"[^\"]*\")])|(\[(\'[^\']*\')])/g);
					var b=n=e=0,ec, // i是正则本次匹配的开始，e是匹配的末尾,ec是末尾的下一个字符，c是总长度，n是上次匹配末尾的位置
						g=0,//匹配上的组号
						s=key,c=s.length,mr,idx;
					while((mr=paramNameReg.exec(key))){
						if(n!=(b=mr.index)){
							throw {name:'格式异常',message:'链式访问格式异常，字符串中间有非法字符'}
						}

						if((idx=mr[(g=1)]||mr[(g=3)]||mr[(g=5)]||mr[(g=7)]||mr[(g=9)]||mr[(g=10)]) && (e=b+mr[0].length)===c){
							ctx.type = g>3?'list':'object';
							ctx.fields.push({indexName:key,fieldName:idx});
							break;
						}

						//因为还没有到末尾，所以还是要新建一个节点
						if(g<=9){
							ctx = ctx.subNodes[idx]= ctx.subNodes[idx]?ctx.subNodes[idx]:dep$.extend(true,{},dnode);//新建一个空子节点,并向子节点移动一层。
						}else
							throw {name:'格式异常',message:'链式访问格式异常，此处应该为.或['};

						n=e;
					}
				}
			});
			return ns;
		};
		var _ret=[];
		var _pick =function(data,pickFields,target){
			var _r = target||{};
			_.each(pickFields,function(p,k){
				if(typeof p == 'string')
					_r[p]=data[p];
				else
					_r[p.fieldName]=data[p.indexName];
			});
			return _r;
		};

		var creatNode = function(root,data,nodeSettings){
			var ns = nodeSettings = dep$.extend(true,nodeSettings||{},{nodeName:'id'});
			var findNode = function(r) {return r[ns.nodeName]==data[ns.nodeName]};

			var curNode= _.find(root,findNode);

			//处理当前节点
			if(!curNode) { // 如果当前节点不存在，则根据配置指定的属性建立一个
				if (_.isArray(root))
					root.push(curNode = _pick(data, ns.fields));
				else
					curNode = _pick(data, ns.fields, root);//取出值放到root里面
			}
			_.each(ns.subNodes,function(sn,idx) {
				!!idx && !_.isArray(curNode[idx]) && (curNode[idx]=(sn.type=='list'?[]:{}));//递归处理List子节点 初始化子数组节点 递归处理Object子节点
				creatNode(curNode[idx], data, sn);
			});

		};

		var doCreateSettings =false;
		_.each(flatDatas,function(data,idx) {
			//根据数据自动完善field,subField,subList参数
			if(!doCreateSettings){
				doCreateSettings = true;
				treeSettings = createSettings(data,treeSettings);
			}
			creatNode(_ret,data, treeSettings);
		});

		return _ret;
	},
	setCookies : function(key,value,path,domain,expires,secure){
		/**设置cookies*/
		/*cookie对象的api = {
		 key:""//不能使用分号（;）、逗号（,）、等号（=）以及空格
		 value:""任意字符串
		 expires: // Date 不设置则当前会话结束后，则失效。
		 path://可访问的目录，不设置则以/为准的所有子页面（含子目录都可以访问）
		 secure: //是否使用https或者其他安全协议进行加密。
		 }

		 两种使用方法:key和value时普通的string，则保存为当前页面路径目录下的k-v cookies

		 当key为对象时，则按如上结构，设置cookie
		 */
		var k,v,e,p,s,d;
		if(typeof key == "object"){
			k = key.key;
			v = key.value;
			e = key.expires;
			p = key.path||"/";
			s = key.secure;
			d = key.domain;
		}else if(typeof key == "string"){
			k = key;
			v = value;
			p = path||"/";
			e = expires;
			s = secure;
			d = domain;
		}

		if(!k || k.indexOf(";")>=0|| k.indexOf(",")>=0|| k.indexOf("=")>=0)
			console.warn("cookie的key设置有误，不能包含;,=及空格。key="+k);

		var str =k+"="+escape(v);

		if(e && e instanceof Date) str = str+";expires="+e.toGMTString();
		if(p && (typeof p == "string")) str = str+";path="+p;
		if(s) str = str+";secure="+(!!e);
		if(d) str = str+";domain="+d;

		document.cookie=str;
	},
	getCookies : function(key){
		/**根据key来获取cookie
		 key可以是
		 ①一个字符串，直接返回一个value值
		 ②以;分割的字符串；返回一个包含kes和value的对象
		 ③一个对象；填充该对象，如果cookies不存在，则该对象的属性为undefined
		 */
		var cookies = document.cookie.split("; ");
		var _t={};
		//_t作缓存，遍历查询
		var findCookie=function(key){
			if(!_t[key]){
				_.find(cookies,function(i){
					var cp = i.split("=");
					_t[cp[0]] = unescape(cp[1]);
					return cp[0] == key;
				});
			}
			return _t[key];
		};

		if(typeof key =="string"){
			if(key.indexOf(";")>=0){
				var ret={};
				_.each(key.split(";"),function(k){
					ret[k]=findCookie(k);
				});
				return ret;
			}else{
				return findCookie(key);
			}
		}else if(typeof key == "object"){
			_.each(key,function(v,k){
				key[k]=findCookie(k);
			});
			return key;
		}
	},
	hasCookie:function (key) {
       return !(!this.getCookies(key) || this.getCookies(key) == 'undefined');
    },
	delCookies : function(key,path){
		/**删除cookies*/
		path=path||"/";
		var d = new Date();
		d.setDate(d.getDate()-1);
		var ds = d.toGMTString();
		document.cookie=key+"=null;path="+path+";expires="+ds;
		document.cookie=key+"=null;domain=."+domain+";path="+path+";expires="+ds;
	},
	getUser: function () {
		return {
			username: RMX.getCookies("UID")
		};
	},
	insertAtCursor : function(html) {
		var str = html instanceof jQuery?html[0].outerHTML:html;
		//if (dep$.browser.msie) {
		//	var range = document.selection.createRange();
		//	txt = range.htmlText + "&nbsp;" + str + "&nbsp;";
		//	range.pasteHTML(txt);
		//}
		//else {
		var sel = window.getSelection();
		if($(sel.anchorNode).parents("[contenteditable]").length==0)
			return;
		var iEnd = sel.anchorOffset;
		var htmldata = sel.anchorNode.data;
		var finaldata =
			((htmldata && htmldata.substring(0, iEnd))||"")
			+ str
			+((htmldata && htmldata.substring(iEnd))||"&nbsp;");
		$(sel.anchorNode).replaceWith(finaldata);
		$(sel.anchorNode).parents("[contenteditable]").focus();
		//}
	},
	isWeixin : function() {
		var ua = navigator.userAgent.toLowerCase();
		if (ua.indexOf("micromessenger") >-1 ) {
			return true;
		} else {
			return false;
		}
	},
	browserName:function(){ //pc端浏览器类型判断
		var userAgent = navigator.userAgent; //取得浏览器的userAgent字符串

		if (userAgent.indexOf("Opera") > -1) {
			return "Opera"
    } //判断是否Opera浏览器
    if (userAgent.indexOf("Firefox") > -1) {
			return "FF";
		} //判断是否Firefox浏览器
		if (userAgent.indexOf("Chrome") > -1){
			return "Chrome";
		}
		if (userAgent.indexOf("Safari") > -1) {
			return "Safari";
		} //判断是否Safari浏览器
		if (userAgent.indexOf("compatible") > -1 && userAgent.indexOf("MSIE") > -1 && !isOpera) {
			return "IE";
    } //判断是否IE浏览器
  },
	decorator:function (beforeFn, wrappedFn,afterFn) {
		var decoratorFn = function () {
			beforeFn && beforeFn.apply(this,arguments);
			wrappedFn && wrappedFn.apply(this,arguments);
			afterFn && afterFn.apply(this,arguments);
		};
		decoratorFn._isDecorator = true;
		return decoratorFn;
	},
	fillFilterData:function (curFilter, data) {
		if(curFilter){
			curFilter._hasData = true;
			_.each(curFilter.rules, function (rule) {
				rule.data = data;
			});
			_.each(curFilter.groups, function (group) {
				RMX.fillFilterData(group, data);
			});
		}
	},
	defaults:function (target/*some defaults...*/) {
		[].shift(arguments);//移除target
		_.each(arguments,function (_defaults) {
			//_.isObject(d)) //数组，对象，日期都是对象。除了基本类型以外都是对象
			_.each(_defaults,function (d,k) {
				if(!_.has(_defaults,k))return;
				var t = target[k];
				if(_.isUndefined(t)){ //如果不存在直接赋值

					if(!_.isObject(d) || _.isFunction(d)){
						target[k] = d;
					}else if(_.isArray(d)){
						target[k]=[];
						_.each(d,function (di,idx) {
							target[k][idx] = (!_.isObject(di) ? di : RMX.defaults(_.isArray(di) ? [] : {}, di));
						})
					}else if(_.isObject(d)){
						target[k]=RMX.defaults({},d);
					}

				}else if(_.isObject(t)){//注意：此处如果是Date function 等内置对象，也会进行直接属性的拷贝
					RMX.defaults(t, d);
				}
			})
		});
		return target;
	},
	phoneModules:function () {//判断android,ios,winphone手机机型
		var u = navigator.userAgent;
		if (u.indexOf('Android') > -1 || u.indexOf('Linux') > -1) {//安卓手机
			return 'Android'
		} else if (u.indexOf('iPhone') > -1) {//苹果手机
			return 'Ios'
		} else if (u.indexOf('Windows Phone') > -1) {//winphone手机
			return 'Winphone'
		}
	},
	isPhone:function () {//判断浏览器是否是移动公司设备
		return navigator.userAgent.match(/(iPhone|iPod|Android|ios)/i) ? true : false
	},
	isIpad: function () { //判断是否是ipad
		return navigator.userAgent.toLowerCase().match(/iPad/i)=="ipad" ? true : false
	},
	testApp: function (url) { //判断手机端是否安装了某个客户端APP
		var timeout, t = 1000, hasApp = true;
		setTimeout(function () {
			if (hasApp) {
				return true
				// alert('安装了app');
			} else {
				return false
				// alert('未安装app');
			}
			document.body.removeChild(ifr);
		}, 2000)

		var t1 = Date.now();
		var ifr = document.createElement("iframe");
		ifr.setAttribute('src', url);
		ifr.setAttribute('style', 'display:none');
		document.body.appendChild(ifr);
		timeout = setTimeout(function () {
			var t2 = Date.now();
			if (!t1 || t2 - t1 < t + 100) {
				hasApp = false;
			}
		}, t);
	},
	openApp:function () {//判断手机是否安装了某个APP,如果安装了就打开，没安装就下载
		var ua = window.navigator.userAgent.toLowerCase();
		//微信
		if(ua.match(/MicroMessenger/i) == 'micromessenger'){
			window.location.href='downLoadForPhone';
		}else{//非微信浏览器
			if (navigator.userAgent.match(/(iPhone|iPod|iPad);?/i)) {
				var loadDateTime = new Date();
				window.setTimeout(function() {
					var timeOutDateTime = new Date();
					if (timeOutDateTime - loadDateTime < 5000) {
						window.location = "";//ios下载地址
					} else {
						window.close();
					}
				},25);
				window.location = "schema://";
			}else if (navigator.userAgent.match(/android/i)) {
				var state = null;
				try {
					window.location = 'schema://';
					setTimeout(function(){
						window.location= ""; //android下载地址

					},500);
				} catch(e) {}
			}
		}
	},
	refresh:function () {
		window.location.reload();
	},
	setHistoryItems: function(keyword, maxNum) { //单行搜索词搜索历史存储
		keyword = keyword.trim()
		let { historyItems } = localStorage
		if (historyItems === undefined) {
			localStorage.historyItems = keyword
		} else if(!!keyword){
			const onlyItem = historyItems.split('|').filter(e => e != keyword)
			if (onlyItem.length > 0 && onlyItem.length <= maxNum ){
				historyItems = keyword + '|' + onlyItem.join('|')
			}else if(onlyItem.length > maxNum){
				onlyItem.pop()
				historyItems = keyword + '|' + onlyItem.join('|')
			}
			localStorage.historyItems = historyItems
			this.historyList = localStorage.historyItems.split("|")
		}
	},
	isSupportSticky: function () { //浏览器是否支持sticky
		var prefixTestList = ['', '-webkit-', '-ms-', '-moz-', '-o-'];
		var stickyText = '';
		for (var i = 0; i < prefixTestList.length; i++ ) {
			stickyText += 'position:' + prefixTestList[i] + 'sticky;';
		}
		// 创建一个dom来检查
		var div = document.createElement('div');
		var body = document.body;
		div.style.cssText = 'display:none;' + stickyText;
		body.appendChild(div);
		var isSupport = /sticky/i.test(window.getComputedStyle(div).position);
		body.removeChild(div);
		div = null;
		return isSupport;
	},
	isIOS6:function () {//是否ios6
		var userAgent = window.navigator.userAgent;
		var ios = userAgent.match(/(iPad|iPhone|iPod)\s+OS\s([\d_\.]+)/);
		return ios && ios[2] && (parseInt(ios[2].replace(/_/g, '.'), 10) >= 6);
	},
	smalltoBIG:function () { //数字金额大写转换(可以处理整数,小数,负数)
		var fraction = ['角', '分'];
		var digit = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'];
		var unit = [ ['元', '万', '亿','兆'], ['', '拾', '佰', '仟','万']  ];
		var head = n < 0? '欠': '';
		n = Math.abs(n);

		var s = '';

		for (var i = 0; i < fraction.length; i++)
		{
			s += (digit[Math.floor(n * 10 * Math.pow(10, i)) % 10] + fraction[i]).replace(/零./, '');
		}
		s = s || '整';
		n = Math.floor(n);

		for (var i = 0; i < unit[0].length && n > 0; i++)
		{
			var p = '';
			for (var j = 0; j < unit[1].length && n > 0; j++)
			{
				p = digit[n % 10] + unit[1][j] + p;
				n = Math.floor(n / 10);
			}
			s = p.replace(/(零.)*零$/, '').replace(/^$/, '零')  + unit[0][i] + s;
		}
		return head + s.replace(/(零.)*零元/, '元').replace(/(零.)+/g, '零').replace(/^整$/, '零元整');
	},
	formatMonet: function (s, n) {//格式化金钱
		n = n > 0 && n <= 20 ? n : 2;
		s = parseFloat((s + "").replace(/[^\d\.-]/g, "")).toFixed(n) + "";
		var l = s.split(".")[0].split("").reverse(),
				r = s.split(".")[1];
		t = "";
		for(i = 0; i < l.length; i ++ )
		{
			t += l[i] + ((i + 1) % 3 == 0 && (i + 1) != l.length ? "," : "");
		}
		return t.split("").reverse().join("") + "." + r;
	}
});
export {RMX}

/**
 * Remex Js extend for jQuery
 */
if(window.jQuery)
(function($) {
 $.ajaxSetup({
	 xhrFields: {withCredentials: true}
 })
})(jQuery);

//基本对象的扩展
/**
 * 扩展String方法
 */
/** @author LIU正数 */
String.prototype.isPositiveInteger = function() {
	return (new RegExp(/^[1-9]\d*$/).test(this));
};
/** 是整数 */
String.prototype.isInteger = function() {return (new RegExp(/^\d+$/).test(this));};
/**是数字*/
String.prototype.isNumber = function(value, element) {return (new RegExp(/^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d+)?$/).test(this));};
/**删除前后空格*/
String.prototype.trim = function() {return this.replace(/(^\s*)|(\s*$)|\r|\n/g, "");};
/**以pattern开始。pattern是普通字符串*/
String.prototype.startsWith = function(pattern) {return this.indexOf(pattern) === 0;};
/**以pattern结束。pattern是普通字符串 */
String.prototype.endsWith = function(pattern) {	var d = this.length - pattern.length;	return d >= 0 && this.lastIndexOf(pattern) === d;};
/**以pattern开始。pattern是普通字符串 */
String.prototype.replaceSuffix = function(index) {
	return this.replace(/\[[0-9]+\]/, '[' + index + ']').replace('#index#', index);
};
String.prototype.trans = function() {
	return this.replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&quot;/g, '"');
};
String.prototype.replaceAll = function(os, ns) {
	return this.replace(new RegExp(os, "gm"), ns);
};

/** 将字符串中{aa_d22}格式的变量根据$data的对象数据进行替换。比如讲aaa{b_1}ccc ,$data={b_1:333},替换成：aaa333ccc*/
String.prototype.replaceTm = function($data) {
	if (!$data)
		return this;
	return this.replace(RegExp("({[A-Za-z_]+[A-Za-z0-9_]*})", "g"), function($1) {
		return $data[$1.replace(/[{}]+/g, "" )];
	});
};
/** 将字符串中{aa_d22}格式的变量根据页面或入参选择器对象中的input对应的数据进行替换。比如讲aaa{b_1}ccc ,<input id="b_1">,替换成：aaa333ccc*/
String.prototype.replaceTmById = function(_box) {
	var $parent = $(_box) || $(document);
	return this.replace(RegExp("({[A-Za-z_]+[A-Za-z0-9_]*})", "g"), function($1) {
		var $input = $parent.find("#" + $1.replace(/[{}]+/g, ""));
		return $input.val() ? $input.val() : $1;
	});
};
/**判断字符串中的{aa_c2}这样的变量是否都已经替换完了。*/
String.prototype.isFinishedTm = function() {
	return !(new RegExp("{[A-Za-z_]+[A-Za-z0-9_]*}").test(this));
};
String.prototype.isValidMail = function() {
	return (new RegExp(/^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/).test(this.trim()));
};
/*是空白字符串*/
String.prototype.isSpaces = function() {
	for ( var i = 0; i < this.length; i += 1) {
		var ch = this.charAt(i);
		if (ch != ' ' && ch != "\n" && ch != "\t" && ch != "\r") {
			return false;
		}
	}
	return true;
};
String.prototype.isPhone = function() {	return (new RegExp(/^1(3[0-9]|4[57]|5[0-35-9]|7[0135678]|8[0-9])\d{8}$/).test(this));};
String.prototype.isEmail = function() {	return (new RegExp(/^([a-zA-Z0-9]+[_|\-|\.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|\-|\.]?)*[a-zA-Z0-9]+(\.[a-zA-Z]{2,3})+$/).test(this));};
String.prototype.isIDCardNo = function() {	return (new RegExp(/(^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$)|(^[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$)/).test(this));};
String.prototype.isUrl = function() {return (new RegExp(/^[a-zA-z]+:\/\/([a-zA-Z0-9\-\.]+)([-\w .\/?%&=:]*)$/).test(this));};
//站外链接
String.prototype.isExternalUrl = function() {return this.isUrl() && this.indexOf("://" + document.domain) == -1;};
/*字符串与日期的转化1*/
String.prototype.parseDate = function(format) {	nd = new Date(this.replaceAll("[年月-]", "/").replaceAll("日","").replaceAll("T"," "));	return nd;};
String.prototype.formatDate = function(format) {return this.parseDate(format).format(format);};
String.prototype.simpleDate = function() {	return this.parseDate("yyyy/MM/dd");};
/** * 根据本字符串生成对应的时间。 */
String.prototype.simpleTime = function() {	return this.parseDate("hh:mm:ss");};
/** 移除本字符串的html标签。*/
String.prototype.removeHtml = function(){	return this.replace(/<[^>].*?>/g,"");  };
/**根据长度省略字符串。超过长度的后补"…" */
String.prototype.omit = function(len) {var s = this.trim();if (s.length > len) {return s.substring(0, len - 3) + "…";} else {return s;}};
/** @param lastIndexChar  */
String.prototype.substrEndByLastIndexChar= function(lastIndexChar){
	var last=0;
	if( typeof(lastIndexChar) === "string")
		last = this.lastIndexOf(lastIndexChar);
	else
		for(var i in lastIndexChar){
			if((last = this.lastIndexOf(lastIndexChar[i]))>0)break;
		}
	return this.substring(0, last);
};

String.prototype.substrStartByLastIndexChar= function(lastIndexChar){
	var last=0;
	if( typeof(lastIndexChar) === "string")
		last = this.lastIndexOf(lastIndexChar);
	else
		for(var i in lastIndexChar){
			if((last = this.lastIndexOf(lastIndexChar[i]))>0)break;
		}
	return this.substring(1+last);
};


String.prototype.substrStartByFirstIndexChar= function(firstIndexChar){
  var index=0;
  if( typeof(firstIndexChar) === "string")
    index = this.indexOf(firstIndexChar);
  else
    for(var i in firstIndexChar){
      if((index = this.lastIndexOf(firstIndexChar[i]))>0)break;
    }
  return this.substring(1+index);
};

String.prototype.isCertNo = function (){
	var idNo = this;
	// 错误码
	var errorCodes =[true,"身份证号码位数错误!","身份证出生日期不合法!","身份证地区不合法!","身份证号码校验错误!"	];
	var area = {11:"北京",12:"天津",13:"河北",14:"山西",15:"内蒙古",21:"辽宁",22:"吉林",23:"黑龙江",31:"上海",32:"江苏",
		33:"浙江",34:"安徽",35:"福建",36:"江西",37:"山东",41:"河南",42:"湖北",43:"湖南",44:"广东",45:"广西",
		46:"海南",50:"重庆",51:"四川",52:"贵州",53:"云南",54:"西藏",61:"陕西",62:"甘肃",63:"青海",64:"宁夏",
		65:"新疆",71:"台湾",81:"香港",82:"澳门",91:"国外"};
	var idNoArray = idNo.split("");

// 地区校验
	if(null == area[parseInt(idNo.substr(0,2))]){
		return errorCodes[3];}

	var reg,checkCode;// 正则表达式,校验码
	var sum,re;// 校验总和，余数
// 身份证位数及格式校验
	switch(idNo.length){
		// 15位校验
		case 15:
			if((parseInt(idNo.substr(6,2))+1900)%4 == 0 || ((parseInt(idNo.substr(6,2))+1900)%100 == 0 && (parseInt(idNo.substr(6,2))+1900)% 4 == 0)){
				reg = /^[1-9][0-9]{5}[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))[0-9]{3}$/;
			}else{
				reg = /^[1-9][0-9]{5}[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|1[0-9]|2[0-8]))[0-9]{3}$/;
			}
			if(reg.test(idNo)){return errorCodes[0];}else{return errorCodes[2];}
			break;
		case 18:
			// 18位校验
			// 出生日期合法性校验
			// 闰年((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))
			// 平年((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|1[0-9]|2[0-8]))
			if(parseInt(idNo.substr(6,4))%4 == 0 || (parseInt(idNo.substr(6,4))%100 == 0&&parseInt(idNo.substr(6,4))%4 == 0)){
				reg = /^[1-9][0-9]{5}((19[0-9]{2})|(200[0-9]{2})|(201[0-3]{2}))((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))[0-9]{3}[0-9Xx]$/;// 闰年校验
			}else{
				reg = /^[1-9][0-9]{5}((19[0-9]{2})|(200[0-9]{2})|(201[0-3]{2}))((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|1[0-9]|2[0-8]))[0-9]{3}[0-9Xx]$/;// 平年
			}
			if(reg.test(idNo)){
				// 校验位
				sum = (parseInt(idNoArray[0])+parseInt(idNoArray[10]))*7
					+ (parseInt(idNoArray[1])+parseInt(idNoArray[11]))*9
					+ (parseInt(idNoArray[2])+parseInt(idNoArray[12]))*10
					+ (parseInt(idNoArray[3])+parseInt(idNoArray[13]))*5
					+ (parseInt(idNoArray[4])+parseInt(idNoArray[14]))*8
					+ (parseInt(idNoArray[5])+parseInt(idNoArray[15]))*4
					+ (parseInt(idNoArray[6])+parseInt(idNoArray[16]))*2
					+ parseInt(idNoArray[7])*1
					+ parseInt(idNoArray[8])*6
					+ parseInt(idNoArray[9])*3;
				re = sum % 11;		// 余数
				checkCode = "10X98765432";			// 校验码
				var checkNo = checkCode.substr(re,1);			// 校验位
				if(checkNo == idNoArray[17])
					return errorCodes[0];
				else
					return errorCodes[4];

			}else{
				return errorCodes[2];
			}
			break;
		default:
			return errorCodes[1];
			break;
	}
};


/*******扩展date**********/
Date.prototype.format = function(format) {
	format = format ||"yyyy-MM-dd";
	var o = {
		"M+" : this.getMonth() + 1, // month
		"d+" : this.getDate(), // day
		"h+" : this.getHours(), // hour
		"m+" : this.getMinutes(), // minute
		"s+" : this.getSeconds(), // second
		"q+" : Math.floor((this.getMonth() + 3) / 3), // quarter
		"S" : this.getMilliseconds()
		// millisecond
	};
	var week = {
		"0" : "日",
		"1" : "一",
		"2" : "二",
		"3" : "三",
		"4" : "四",
		"5" : "五",
		"6" : "六"
	};
	if (/(y+)/.test(format))
		format = format.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
	if(/(E+)/.test(format)){
		format=format.replace(RegExp.$1, ((RegExp.$1.length>1) ? (RegExp.$1.length>2 ? "星期" : "/u5468") : "")+week[this.getDay()+""]);
	}
	for ( var k in o)
		if (new RegExp("(" + k + ")").test(format))
			format = format.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length));
	return format;
};
Date.prototype.simpleDate = function(splitString) {
	var sd = splitString?this.format("yyyy"+splitString+"MM"+splitString+"dd"):this.format("yyyy-MM-dd");
	return sd=="NaN-aN-aN"?"":sd;
};
Date.prototype.simpleTime = function(splitString) {
	var sd = splitString?this.format("yyyy"+splitString+"MM"+splitString+"dd"):this.format("hh-mm-ss");
	return sd=="NaN-aN-aN"?"":sd;
};
Date.prototype.moveDate = function(oper,format){
	var m;
	if(m=/([yMdh])([\+\-])([\dse]+)/.exec(oper))
		switch (m[1]) {
			case "h":
				if(m[3]=="e") {//h末
					this.setHours(this.getMinutes() + 1);
					this.setMinutes(1);
					this.setMinutes(this.getMinutes()-1);
				}else if(m[3]=='s') {//h初
					this.setMinutes(0);
				}else if(m[2]=="+")
					this.setHours(this.getHours()+parseInt(m[3]));
				else
					this.setHours(this.getHours()-parseInt(m[3]));
				break;
			case "d":
				if(m[2]=="+")
					this.setDate(this.getDate()+parseInt(m[3]));
				else
					this.setDate(this.getDate()-parseInt(m[3]));
				break;
			case "M":
				if(m[3]=="e") {//月末
					this.setMonth(this.getMonth() + 1);
					this.setDate(1);
					this.setDate(this.getDate()-1);
				}else if(m[3]=='s') {//月初
					this.setDate(1);
				}else if(m[2]=="+")
					this.setMonth(this.getMonth()+parseInt(m[3]));
				else
					this.setMonth(this.getMonth()-parseInt(m[3]));
				break;
			case "y":
				if(m[2]=="+")
					this.setYear(this.getFullYear()+parseInt(m[3]));
				else
					this.setYear(this.getFullYear()-parseInt(m[3]));
				break;

			default:
				throw "未实现的操作"+oper;
		}
	return this;
};
Date.prototype.toChineseDate = function() {
	//日期转中文
	// 数字时间转化为汉字时间
// 1、获取中文年
	var myDate=this;
	var cnDate = [["0","〇"],["1","一"],["2","二"],["3","三"],["4","四"],["5","五"],["6","六"],["7","七"],["8","八"],["9","九"],["10","十"],["11",'十一'],["12","十二"]];
	function getCFullYear(){
		myFullYear=myDate.getFullYear().toString().split("");
		for(var i=0;i<myFullYear.length;i++){
			j=parseInt(myFullYear[i]);
			myFullYear[i]=cnDate[j][1];
		}
		myFullYear=myFullYear.join("");
		return myFullYear;
	}
// 2、获取中文月
	function getCMonth(){
		myMonth=myDate.getMonth().toString();
		j=parseInt(myMonth)+1;
		myMonth=cnDate[j][1];
		return myMonth;
	}
// 3、获取中文日
	function getCToday(){
		myToday=parseInt(myDate.getDate());
		if(myToday<=10){
			myToday=cnDate[myToday][1];
		}else if(myToday>10&&myToday<20){
			myToday='十'+cnDate[myToday%10][1];
		}else if(myToday==20){
			myToday='二十';
		}else if(myToday>20&&myToday<30){
			myToday='二十'+cnDate[myToday%10][1];
		}else if(myToday==30){
			myToday='三十';
		}else{
			myToday='三十'+cnDate[myToday%10][1];
		}
		return myToday;
	}

// 4、获取中文年月日(单次获得)
	var myCFullYear=getCFullYear()+'年';
	var myCMonth=getCMonth()+'月';
	var myCToday=getCToday()+'日';
	return myCFullYear+myCMonth+myCToday;
};


/**扩展Array*/
Array.prototype.remove = function(ele) {
	var ctx = this;
	//rmx 添加的方法，删除指定的数组item
	_.each(_.isArray(ele)?ele:[ele],function (ele) {
		var idx = ctx.indexOf(ele);
		if(idx>=0)
			ctx.splice(idx,1);
	});
};
Array.prototype.togglePush = function (ele,predicateField) {
	var idx = predicateField?_.findIndex(this,function(i){return i[predicateField]==ele[predicateField]}):this.indexOf(ele);
	if(idx>=0){
		this.splice(idx,1);
	}else{
		this.push(ele);
	}
};
Array.prototype.last = function () {
	if(this.length > 0){
		return this[this.length - 1]
	}
	else{
		return undefined
	}
};
Array.prototype.contains =function(ele,predicateField){
	var idx = predicateField?_.findIndex(this,function(i){return i[predicateField]==ele[predicateField]}):this.indexOf(ele);
	return idx>=0;
};
Array.prototype.aggregateFunctions={
	get:function (aggrFun) {
		if(typeof aggrFun ==='string'){
			return this[aggrFun];
		}else{
			return aggrFun;
		}
	},
	SUM:function (aggrResult, val) {
		return parseFloat(aggrResult||0)+parseFloat(val||0);
	}
};
Array.prototype.part = function (start, count, stop) {
	var stop = start + count;
	_.partition(this,function (i, idx) {
		return idx >= idx && idx < stop;
	})
};

Array.prototype.aggregateBy = function (aggrFun,opt) {
	var _aggrFun=this.aggregateFunctions.get(aggrFun),aggrResult;

	if(typeof  opt === 'string')
		_.each(this,function (item) {
			aggrResult = _aggrFun.call(this, aggrResult, item[opt]);
		});
	return aggrResult;
};
Number.prototype.ceil = function () {
	return Math.ceil(this);
};

//银行卡卡号校验
String.prototype.lunCheck = function (bankno){
  var lastNum=bankno.substr(bankno.length-1,1);//取出最后一位（与luhn进行比较）

  var first15Num=bankno.substr(0,bankno.length-1);//前15或18位
  var newArr=new Array();
  for(var i=first15Num.length-1;i>-1;i--){    //前15或18位倒序存进数组
    newArr.push(first15Num.substr(i,1));
  }
  var arrJiShu=new Array();  //奇数位*2的积 <9
  var arrJiShu2=new Array(); //奇数位*2的积 >9

  var arrOuShu=new Array();  //偶数位数组
  for(var j=0;j<newArr.length;j++){
    if((j+1)%2==1){//奇数位
      if(parseInt(newArr[j])*2<9)
        arrJiShu.push(parseInt(newArr[j])*2);
      else
        arrJiShu2.push(parseInt(newArr[j])*2);
    }
    else //偶数位
      arrOuShu.push(newArr[j]);
  }

  var jishu_child1=new Array();//奇数位*2 >9 的分割之后的数组个位数
  var jishu_child2=new Array();//奇数位*2 >9 的分割之后的数组十位数
  for(var h=0;h<arrJiShu2.length;h++){
    jishu_child1.push(parseInt(arrJiShu2[h])%10);
    jishu_child2.push(parseInt(arrJiShu2[h])/10);
  }

  var sumJiShu=0; //奇数位*2 < 9 的数组之和
  var sumOuShu=0; //偶数位数组之和
  var sumJiShuChild1=0; //奇数位*2 >9 的分割之后的数组个位数之和
  var sumJiShuChild2=0; //奇数位*2 >9 的分割之后的数组十位数之和
  var sumTotal=0;
  for(var m=0;m<arrJiShu.length;m++){
    sumJiShu=sumJiShu+parseInt(arrJiShu[m]);
  }

  for(var n=0;n<arrOuShu.length;n++){
    sumOuShu=sumOuShu+parseInt(arrOuShu[n]);
  }

  for(var p=0;p<jishu_child1.length;p++){
    sumJiShuChild1=sumJiShuChild1+parseInt(jishu_child1[p]);
    sumJiShuChild2=sumJiShuChild2+parseInt(jishu_child2[p]);
  }
  //计算总和
  sumTotal=parseInt(sumJiShu)+parseInt(sumOuShu)+parseInt(sumJiShuChild1)+parseInt(sumJiShuChild2);

  //计算luhn值
  var k= parseInt(sumTotal)%10==0?10:parseInt(sumTotal)%10;
  var luhn= 10-k;

  if(lastNum==luhn){
    return true;
  }
  else{
    return false;
  }
}


